package webcenter

import (
	"fmt"
	"net/http"
	"strings"

	"log"
	"sync"

	"github.com/kataras/iris/v12"
	Icontext "github.com/kataras/iris/v12/context"
)

var (
	//WebCenter
	once  sync.Once
	defWh *WebCenter = nil
)

//Web 插件初始化函数
type FuncWebPluginInit func(*WebCenter) error

//注册Web插件初始化 ,  由WebCenter执行 Web插件的初始化设置
func RegisterWebPlugin(pluginName string, p WebPlugin) {
	wh := GetWebCenter()
	wh.RegisterWebPlugin(pluginName, p)
}

type WebCenter struct {
	app      *iris.Application
	appBuild bool //表示 app 是否已经build, 如果已经build则不再build
	//cfg       *config.ServiceConfig
	mapPlugin map[string]WebPlugin
	mapWh     map[string]interface{} //iris.Handler
	mapRoute  map[string]WebRoute
}

type WebRoute struct {
	Method string //多个方法使用空格分隔
	// method 为static 时， selector 表示 静态目录
	Selector string // 表示 服务名或静态目录
	// 表示服务名时， 服务名必须内部注册才有效
	Party string // 分组路由， 如果有， 实际URL 应该为/Party/Path
	Path  string // 路由地址
}

func GetWebCenter() *WebCenter {
	once.Do(func() {
		defWh = newWebHandler()
	})
	return defWh
}

func newWebHandler() *WebCenter {
	wh := new(WebCenter)

	wh.app = iris.New()
	wh.app.Logger().SetLevel("info")

	wh.appBuild = false

	wh.mapPlugin = make(map[string]WebPlugin) // 插件map
	wh.mapWh = make(map[string]interface{})   // 服务 与 处理函数之间map, 如果是静态目录，可以是string 或者是 fs
	wh.mapRoute = make(map[string]WebRoute)   // 服务 与 http 路由 之间的map

	//w.app.HandleDir("/swagger", "./static/swagger")
	//
	return wh
}

//初始化设置, 执行各webPlugin的初始化函数
func (w *WebCenter) Init() {

}

//注册web插件
//注册服务对应的处理函数
func (w *WebCenter) RegisterWebPlugin(serviceName string, p WebPlugin) {
	//service全部转换为小写
	w.mapPlugin[strings.ToLower(serviceName)] = p

}

//注册服务对应的处理函数
func (w *WebCenter) RegisterWebHandler(serviceName string, h interface{}) {
	//service全部转换为小写
	w.mapWh[strings.ToLower(serviceName)] = h

}

//设置Http路由, method 为static 表示静态目录
func (w *WebCenter) SetHttpRoute(httpMethod string, party string, path string, service string) {
	sn := strings.ToLower(service)
	key := sn + "_" + httpMethod + "_" + path
	w.mapRoute[key] = WebRoute{
		Selector: sn,
		Method:   httpMethod,
		Path:     path,
		Party:    party,
	}
}

func (w *WebCenter) Start() {
	if !w.appBuild {
		//执行各WebPlugin的初始化设置
		for name, plugin := range w.mapPlugin {
			log.Println("WebCenter register plugin ", name)
			plugin.Register(w)
		}

		// //设置路由
		// for _, r := range cfg.Routes {
		// 	w.SetHttpRoute(r.Method, r.Party, r.Path, r.Selector)
		// }

		w.appBuild = true

		//分组
		partyList := make(map[string]iris.Party)
		//循环添加路由
		for _, r := range w.mapRoute {
			// log.Info("--------------------v", zap.Reflect("v", r))
			var rp iris.Party
			if 0 < len(r.Party) {
				if pl, bExist := partyList[r.Party]; bExist {
					rp = pl
				} else {
					rp = w.app.Party(r.Party)

					rp.Use(w.before)
					rp.Done(w.after)
					partyList[r.Party] = rp

				}
			} else {
				rp = w.app
			}
			//log.Error("GetHttpHandler", zap.Reflect("r",r ), zap.Reflect("rp",rp ))

			if h, ok := w.mapWh[r.Selector]; ok {
				if r.Method == "static" {
					//log.Printf("WebCenter party register static path[%s]  [%v] ", r.Path, h)
					rp.HandleDir(r.Path, h)

				} else {
					//if ch, chOk := h.(context.Handler); chOk {
					if ch, chOk := h.(Icontext.Handler); chOk {
						rp.HandleMany(r.Method, r.Path, ch)
					} else if ich, chOk := h.(func(*Icontext.Context)); chOk {
						rp.HandleMany(r.Method, r.Path, ich)
					} else {
						log.Printf("WebCenter party register handler: Bad handler [%T] %v\n ", h, r)
					}
				}
			} else {
				//error
				log.Printf("WebCenter party register handler: Selector [%v] not found\n ", r.Selector)
			}

		}

		w.app.Build()
	}
	rs := w.app.GetRoutes()
	for k, r := range rs {
		fmt.Println(k, r)
	}
}

func (w *WebCenter) Run(addr string) {
	w.app.Run(iris.Addr(addr))
}

func (w *WebCenter) Stop() {

}

//该函数只能执行一次
func (w *WebCenter) GetHttpHandler() http.Handler {
	//设置实际http路由

	return w.app
}

func (w *WebCenter) before(ctx iris.Context) {
	//...
	req := ctx.RequestPath(true)
	log.Println("http before", "RequestPath(true)", req)
	ctx.Next()

}

func (w *WebCenter) after(ctx iris.Context) {

	ctx.Next()
}
